/*==========================================================================*\
 |  $Id: UiFactory.java 23 2009-11-08 18:22:35Z VTWoods $
 |*-------------------------------------------------------------------------*|
 |  Copyright (C) 2009 Virginia Tech
 |
 |  This file is part of CloudSpace.
 |
 |  CloudSpace is free software; you can redistribute it and/or modify
 |  it under the terms of the GNU General Public License as published
 |  by the Free Software Foundation; either version 3 of the License, or
 |  (at your option) any later version.
 |
 |  CloudSpace is distributed in the hope that it will be useful,
 |  but WITHOUT ANY WARRANTY; without even the implied warranty of
 |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 |  GNU General Public License for more details.
 |
 |  You should have received a copy of the GNU General Public License
 |  along with CloudSpace; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/

package student.web.internal;

import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Field;
import java.util.List;

import org.zkoss.idom.Document;
import org.zkoss.zk.ui.http.SimpleUiFactory;
import org.zkoss.zk.ui.metainfo.InitiatorInfo;
import org.zkoss.zk.ui.metainfo.PageDefinition;
import org.zkoss.zk.ui.sys.RequestInfo;
import org.zkoss.zkplus.databind.AnnotateDataBinderInit;


//-------------------------------------------------------------------------
/**
 *  A custom UI factory for student ZK pages that implicitly adds
 *  an {@link Initializer} to any page definitions it loads.
 *
 *  @author Stephen Edwards
 *  @author Last changed by $Author: VTWoods $
 *  @version $Revision: 23 $, $Date: 2009-11-08 18:22:35 +0000 (Sun, 08 Nov 2009) $
 */
public class UiFactory
    extends SimpleUiFactory
{
    // ----------------------------------------------------------
    @Override
    public PageDefinition getPageDefinition( RequestInfo ri, String path )
    {
        return wrap( super.getPageDefinition( ri, path ) );
    }


    // ----------------------------------------------------------
    @Override
    public PageDefinition getPageDefinitionDirectly(
        RequestInfo ri, Document content, String extension )
    {
        return wrap(super.getPageDefinitionDirectly( ri, content, extension ));
    }


    // ----------------------------------------------------------
    @Override
    public PageDefinition getPageDefinitionDirectly(
        RequestInfo ri, Reader reader, String extension )
        throws IOException
    {
        return wrap(super.getPageDefinitionDirectly( ri, reader, extension ));
    }


    // ----------------------------------------------------------
    @Override
    public PageDefinition getPageDefinitionDirectly(
        RequestInfo ri, String content, String extension )
    {
        return wrap(super.getPageDefinitionDirectly( ri, content, extension ));
    }


    // ----------------------------------------------------------
    @SuppressWarnings("unchecked")
	private PageDefinition wrap( PageDefinition pagedef )
    {
    	
        if (pagedef != null)
        {
        	// First, get the _initdefs field, if we haven't already
        	if (_initdefs == null)
        	{
        		for (Field f : PageDefinition.class.getDeclaredFields())
        		{
        			if (f.getName().equals("_initdefs"))
        			{
        				f.setAccessible(true);
        				_initdefs = f;
        				break;
        			}
        		}
        	}

        	// Now look for an existing initiator
        	try
        	{
        		List<InitiatorInfo> list =
        			(List<InitiatorInfo>)_initdefs.get(pagedef);
        		if (list != null)
        		{
        			// We need to get the initiator info's internal field
                	if (_init == null)
                	{
                		for (Field f : InitiatorInfo.class.getDeclaredFields())
                		{
                			if (f.getName().equals("_init"))
                			{
                				f.setAccessible(true);
                				_init = f;
                				break;
                			}
                		}
                	}

                	// Now, scan the list looking for the right one
                	for (InitiatorInfo info: list)
        			{
                		Object i = _init.get(info);
        				if (i != null
        					&& (i == Initializer.class
        						|| AnnotateDataBinderInit.class
        							.isAssignableFrom(i.getClass())))
        				{
        					// If found, don't add it again
        					return pagedef;
        				}
        			}
        		}
        	}
        	catch (Exception e)
        	{
        		// swallow it
        		e.printStackTrace();
        	}

        	// If we didn't find this initiator, then add it
        	pagedef.addInitiatorInfo(
                new InitiatorInfo( Initializer.class, (String[])null ) );
        }
        return pagedef;
    }


    // ----------------------------------------------------------
    private static Field _initdefs = null;
    private static Field _init = null;
}
